#include "networkcapturethread.h"


NetworkCaptureThread::NetworkCaptureThread()
{
    char filter_exp[] = "";

    dev = pcap_lookupdev(errbuf);
    if(dev == NULL){
        printf("pcap_lookupdev : %s\n", errbuf);
        exit(1);
    }
    printf("DEVICE:%s\n", dev);

    ret = pcap_lookupnet(dev, &netp, &maskp, errbuf);
    if(ret == -1){
        printf("pcap_lookupnet : %s\n", errbuf);
        exit(1);
    }

    descr = pcap_open_live(dev, BUFSIZ, 0, 0, errbuf);
    if(descr == NULL){
        printf("pcap_open_live():%s\n",errbuf);
        exit(1);
    }

    if(pcap_compile(descr, &fp, filter_exp, 0, maskp) == -1){
        fprintf(stderr,"pcap_compile() error\n");
        exit(1);
    }

    if(pcap_setfilter(descr, &fp) == -1){
        fprintf(stderr,"pcap_setfilter() error\n");
        exit(1);
    }
}

NetworkCaptureThread::~NetworkCaptureThread(){

    pcap_close(descr);
}

void NetworkCaptureThread::TcpPktCallback(u_char *argument, const struct pcap_pkthdr *packet, const u_char *packet_content){
    struct tcphdr *tcp_protocol;
    u_int16_t srcPort;    //源端口
    u_int16_t dstPort;    //目的端口
    u_int32_t sequence; //序号
    u_int32_t acknowledgement;//确认号
    u_int16_t headerLength;
    u_char flags;
    u_int16_t windows;   //窗口大小
    u_int16_t checksum;    //校验和
    u_int16_t urgentOffset;//



    u_int16_t	ipLength;
    struct ip *ip_protocol;
//    map<int,SERVE_FLOW>::iterator it;
//    map<int,long>::iterator position;

    ip_protocol=(struct ip*)(packet_content+14);
    ipLength=ntohs(ip_protocol->ip_len);

    printf("----tcp protocol-----\n ");
    tcp_protocol=(struct tcphdr *)(packet_content+14+20);

    //源端口
    srcPort=ntohs(tcp_protocol->source);
    printf("源端口: \t%d\n",srcPort);

    //
    dstPort=ntohs(tcp_protocol->dest);
    printf("目的端口:\t%d\n",dstPort);

    //
    sequence=ntohl(tcp_protocol->seq);
    printf("sequence Number:\t%u\n",sequence);

    //
    acknowledgement=ntohl(tcp_protocol->ack_seq);
    printf("Acknowlegement Number:%u\n",acknowledgement);

    // MARK MY SUSPICIOUS
    headerLength=tcp_protocol->doff*4;
    printf("header length:\t%d\n",headerLength);

    //FLAGS
    printf("Flags:");
    if(tcp_protocol->urg & 0x20)
        printf("URG");
    if(tcp_protocol->ack & 0x10)
        printf("ACK");
    if(tcp_protocol->psh & 0x08)
        printf("PSH");
    if(tcp_protocol->rst & 0x04)
        printf("RST");
    if(tcp_protocol->syn & 0x02)
        printf("SYN");
    if(tcp_protocol->fin & 0x01)
        printf("FIN");
    printf("\n");

    //
    windows=ntohs(tcp_protocol->window);
    printf("Windows size:\t%d\n",windows);

    //
    checksum=ntohs(tcp_protocol->check);
    printf("校验和:\t%d\n",checksum);

    //
    urgentOffset=ntohs(tcp_protocol->urg_ptr);
    printf("urgentOffset:\t%d\n",urgentOffset);

}

void NetworkCaptureThread::UdpPktCallback(u_char *argument, const struct pcap_pkthdr *packet, const u_char *packet_content){
    struct udphdr *udp_protocol;    //udp首部指针

    u_short srcPort;
    u_short dstPort;
    short udpLength;
    u_short cksum;
    u_int16_t	ipLength;
    struct ip *ip_protocol;

         //map<int,long>::iterator pos;
    ip_protocol=(struct ip*)(packet_content+14);
    ipLength=ntohs(ip_protocol->ip_len);

    udp_protocol=(struct udphdr *)(packet_content+14+20);//跳过了Ethernet和IP首部
    printf("                  ----udp protocol-----\n ");
    //源端口
    srcPort = ntohs(udp_protocol->source);
    printf("源端口：\t%d\n",srcPort);

    //目的端口
    dstPort = ntohs(udp_protocol->dest);
    printf("目的端口:\t%d\n",dstPort);

    //根据目的端口判断服务类型
    //UDP长度
    udpLength = ntohs(udp_protocol->len);
    printf("UDP长度:\t%d\n",udpLength);

    //UDP校验和
    cksum = ntohs(udp_protocol->check);
    printf("UDP校验和：\t%d\n",cksum);

}

void NetworkCaptureThread::IcmpPktCallback(u_char *argument, const struct pcap_pkthdr *packet, const u_char *packet_content){
    struct icmphdr *icmp_protocol;
    u_char type;//ICMP类型
    u_char code;//ICMP类型子码
    u_short cksum;//

    printf("                     -------ICMP协议--------");
    icmp_protocol=(struct icmphdr *)(packet_content+14+20);

    //ICMP类型
    type = icmp_protocol->type;
    printf("ICMP特定标识:\t%d\n",type);
    switch(type)
    {
    case ICMP_ECHO://回应信息
    case ICMP_ECHOREPLY:
        printf("echo %s\n",(type == ICMP_ECHO)?"request":"reply");
        code = icmp_protocol->code;
        printf("子码:\t%d\n",code);

        cksum = icmp_protocol->checksum;
        printf("校验码:\t%d\n",cksum);
        break;
//    case ICMP_DEST_UNREACH:
//        switch(icmp_protocol->code)
//        {
//        case ICMP_PROT_REACH://Protocol Unreachable
//
//
//
//        }
//        printf("ICMP Echo Request Protocol\n");
//        printf("ICMP Code:%d\n",icmp_protocol->icmp_code);
//        printf("ICMP Identifier:%d\n",icmp_protocol->icmp_id);
//        printf("Sequence Number:%d\n",icmp_protocol->icmp_sequence);
//        sicc++;
//        break;

    default:
        break;
    }
}

void NetworkCaptureThread::ArpPktCallback(u_char *argument, const struct pcap_pkthdr *packet, const u_char *packet_content){
    struct ether_arp *arp_protocol;

    u_short macFormat;//硬件地址类型
    u_short protocolAddressFormat;//协议地址类型
    u_char macLength;//硬件地址长度
    u_char protocolAddressLength;//协议地址长度
    u_short operationCode;  //ARP／RARP操作码
    u_char *srcMac,*dstMac;//源MAC,目的MAC
    u_char *strSrcIP,*strDstIP;//源IP,目的IP字符串表示
    struct in_addr srcIP;
    struct in_addr dstIP;

    printf("           ------ARP Protocol-----\n");
    arp_protocol=(struct ether_arp*)(packet_content+14);

    //硬件地址类型
    macFormat = ntohs(arp_protocol->ar_hrd);
    printf("ARP 硬件地址类型:\t%d\n",macFormat);

    //协议地址类型
    protocolAddressFormat = ntohs(arp_protocol->ar_pro);
    printf("ARP 协议地址类型:\t%d\n",protocolAddressFormat);

    //硬件地址长度
    macLength = ntohs(arp_protocol->ar_hln);
    printf("ARP 硬件地址长度:\t%d\n",macLength);

    //协议地址长度
    protocolAddressLength = ntohs(arp_protocol->ar_pln);
    printf("ARP 协议地址长度:\t%d\n",protocolAddressLength);

    //操作码
    operationCode = ntohs(arp_protocol->ar_op);
    printf("ARP 操作码:\t%d\n",operationCode);
    switch(operationCode)
    {
    case 1:
        printf("ARP Request Protocol\n");
        break;
    case 2:
        printf("ARP Reply Protocol\n");
        break;
    case 3:
        printf("RARP Request Protocol\n");
        break;
    case 4:
        printf("RARP Reply Protocol\n");
        break;
    default:
        break;
    }

    //源MAC
    srcMac = arp_protocol->ar_sha;
    printf("源MAC:\t%02x:%02x:%02x:%02x:%02x:%02x\n",*srcMac,*(srcMac+1),*(srcMac+2),*(srcMac+3),*(srcMac+4),*(srcMac+5));

    //源IP地址
    strSrcIP = arp_protocol->ar_spa;
    memcpy((void*)&srcIP,(void*)&strSrcIP,sizeof(struct in_addr));
    printf("源IP地址:\t%s\n",inet_ntoa(srcIP));

    //目的MAC
    dstMac = arp_protocol->ar_tha;
    printf("目的MAC:\t%02x:%02x:%02x:%02x:%02x:%02x\n",*dstMac,*(dstMac+1),*(dstMac+2),*(dstMac+3),*(dstMac+4),*(dstMac+5));

    //目的IP地址
    strDstIP = arp_protocol->ar_tpa;
    memcpy((void*)&dstIP,(void*)&strDstIP,sizeof(struct in_addr));
    printf("目的IP地址:\t%s\n",inet_ntoa(dstIP));
}

void NetworkCaptureThread::IpPktCallback(u_char *argument, const struct pcap_pkthdr *packet, const u_char *packet_content){
    struct ip *ip_protocol;
    u_int header_length;//IP 首部长度
    u_int offset;
    u_char tos;
    u_int16_t checksum;
    u_int length;
    u_int hlen;
    u_int version;  //IP 版本
    u_int len;

    //ipc++;

    //14为ethernet II首部长度
    ip_protocol=(struct ip*)(packet_content+14);

    printf("           ------IP Protocol------\n");

    //输出IP首部信息
    //IP 版本
    version = IP_V(ip_protocol);
    if(version == 4)
        printf("IP 版本:\t%d\n",version);
    else
        printf("Unknown Version: %d\n",version);

    //IP 首部长度
    uint16_t  hLen = IP_HL(ip_protocol);
    if(hLen < 5)
        printf("bad IP packet:IP header is too short\n");
    header_length = hLen * 4;
    if(header_length < sizeof(struct ip))
    {
        printf("bad len: %u\n",header_length);
        return;
    }
    printf("IP 首部长度:\t%d\n",header_length);

    //服务类型，区分实时数据包和非实时数据包
    tos = ip_protocol->ip_tos;
    printf("服务类型:\t%d\n",tos);

    //IP数据包长度
    length = packet->len;//dump数据包的总长度
    length -= sizeof(struct ether_header);
    length -= 4;//减去CRC校验的长度
    if(length < sizeof(struct ip))
    {
        printf("truncated ip %d",length);
        return ;
    }

    len=ntohs(ip_protocol->ip_len); //length should be equal to len
    if(length<len)
    {
        printf("\n truncated IP -%d bytes missing\n",len-length);
    }
    printf("IP数据包长度:\t%d\n",len);

    //IP数据包ID
    printf("IP数据包ID:\t%d\n",ntohs(ip_protocol->ip_id));

    //偏移量
    offset = ntohs(ip_protocol->ip_off);
    printf("偏移量:\t%d\n",(offset&0x1fff)*8);

    //TTL
    printf("TTL:%d\n",ip_protocol->ip_ttl);

    //网络层协议
    u_int8_t protocol = ip_protocol->ip_p;
    switch(protocol)
    {
    case 1:
        printf("The Transport Layer Protocol is ICMP\n");
        IcmpPktCallback(argument,packet,packet_content);
        break;
    case 6:
        printf("The Transport Layer Protocol is TCP\n");
        //tcp_protocol_packet_callback(argument,packet_header,packet_content);
        break;
    case 17:
        printf("The Transport Layer Protocol is UDP\n");
        //udp_protocol_packet_callback(argument,packet_header,packet_content);
        break;
    default:
        break;
    }

    //checksum
    checksum=ntohs(ip_protocol->ip_cksum);
    printf("校验和 :\t%d\n",checksum);

    //源IP地址
    printf("源IP地址:\t%s\n",inet_ntoa(ip_protocol->ip_src));

    //目的IP地址
    printf("目的IP地址:\t%s\n",inet_ntoa(ip_protocol->ip_dst));
}

void NetworkCaptureThread::EthernetPktCallback(u_char *argument, const struct pcap_pkthdr *packet, const u_char *packet_content){

    u_short ethernet_type;  //ethernet 类型
    struct ether_header *ethernet_protocol;
    u_char *mac_string;
    static int packet_number=1;

    printf("**********************************************\n");
    printf("The %d packet is captured .\n ",packet_number);
    printf("----------------Ethernet Protocol---------------\n");
    ethernet_protocol = (struct ether_header*)packet_content;

    ethernet_type = ntohs(ethernet_protocol->ether_type);
    printf("Ethernet type is: %04x\n",ethernet_type);

    switch(ethernet_type)
    {
    case 0x0800:
        printf("the network layer is IP protocol\n");
        break;
    case 0x0806:
        printf("the network layer is ARP protocol\n");
        break;
    case 0x8035:
        printf("the network layer is RARP protocol\n");
        break;
    default:
        break;
    }

    printf("Mac Source Address is : ");
    mac_string=ethernet_protocol->ether_shost;
    printf("%02x:%02x:%02x:%02x:%02x:%02x\n",*mac_string,*(mac_string+1),*(mac_string+2),*(mac_string+3),*(mac_string+4),*(mac_string+5));


    switch(ethernet_type)
    {
    case 0x0800:
        IpPktCallback(argument,packet,packet_content);
        break;
    case 0x0806:
        ArpPktCallback(argument,packet,packet_content);
        break;
    default:
        break;
    }

    packet_number++;
    printf("**********************************************\n");
}

void NetworkCaptureThread::run(){

    pcap_loop(descr, -1, EthernetPktCallback, NULL);

}
